﻿using IRepositories.BASE;
using Microsoft.EntityFrameworkCore;
using Repositories.EfContext;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using System.Linq.Dynamic.Core;

namespace Repositories.BASE
{
    public class BaseRespository<TEntity> : IBaseRepository<TEntity> where TEntity : class, new()
    {
        private SwiftCodeBbsContext _context;

        public BaseRespository()
        {
            _context = new SwiftCodeBbsContext();
        }
        protected SwiftCodeBbsContext Dbtext() 
        { return _context; }
        public async Task DeleteAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default)
        {
            _context.Set<TEntity>().Remove(entity);
            if (autoSave)
            {
                await _context.SaveChangesAsync(cancellationToken);
            }
        }

        public async Task DeleteAsync(Expression<Func<TEntity, bool>> expression, bool autoSave = false, CancellationToken cancellationToken = default)
        {
            var dbSet = _context.Set<TEntity>();
            var entities = await dbSet.Where(expression).ToListAsync(cancellationToken);
            await DeleteManyAsync(entities, autoSave, cancellationToken);
            if (autoSave)
            {
                await _context.SaveChangesAsync(cancellationToken);
            }
        }

        public async Task DeleteManyAsync(IEnumerable<TEntity> entities, bool autoSave = false, CancellationToken cancellationToken = default)
        {
            _context.RemoveRange(entities, autoSave);
            if (autoSave)
            {
                await _context.SaveChangesAsync(cancellationToken);
            }
        }

        public Task<TEntity> FindAsync(Expression<Func<TEntity, bool>> expression, CancellationToken cancellationToken = default)
        {
            return _context.Set<TEntity>().Where(expression).SingleOrDefaultAsync(cancellationToken);
        }

        public Task<TEntity> GetAsync(Expression<Func<TEntity, bool>> expression, CancellationToken cancellationToken = default)
        {
            var entity =  FindAsync(expression, cancellationToken);
            if(entity == null)
            {
                throw new Exception(nameof(TEntity) + "null");
            }
            return entity;
        }

        public Task<long> GetCountAsync(CancellationToken cancellationToken = default)
        {
            return _context.Set<TEntity>().LongCountAsync(cancellationToken);
        }

        public Task<long> GetCountAsync(Expression<Func<TEntity, bool>> expression, CancellationToken cancellationToken = default)
        {
            return _context.Set<TEntity>().Where(expression).LongCountAsync(cancellationToken);
        }

        public Task<List<TEntity>> GetListAsync(CancellationToken cancellationToken = default)
        {
            return _context.Set<TEntity>().ToListAsync(cancellationToken);
        }

        public Task<List<TEntity>> GetListAsync(Expression<Func<TEntity, bool>> expression, CancellationToken cancellationToken = default)
        {
            return _context.Set<TEntity>().Where(expression).ToListAsync(cancellationToken);
        }

        private bool OrderBy(string str)
        {
            return true;
        }
        public Task<List<TEntity>> GetPagedListAsync(int skipCount, int maxResultCount, string sorting, CancellationToken cancellationToken = default)
        {
            //throw new NotImplementedException();
            return _context.Set<TEntity>().OrderBy(sorting).Skip(skipCount).Take(maxResultCount).ToListAsync(cancellationToken);
        }

        public async Task<TEntity> InsertAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default)
        {
            var saveEntity = (await _context.Set<TEntity>().AddAsync(entity, cancellationToken)).Entity;
            if (autoSave)
            {
                await _context.SaveChangesAsync(cancellationToken);
            }

            return saveEntity;
        }

        public async Task InsertManyAsync(IEnumerable<TEntity> entities, bool autoSave = false, CancellationToken cancellationToken = default)
        {
            var entityArray = entities.ToArray();
            await _context.Set<TEntity>().AddRangeAsync(entityArray, cancellationToken);
            if (autoSave)
            {
                await _context.SaveChangesAsync(cancellationToken);   
            }
        }

        public async Task<TEntity> UpdateAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default)
        {
            _context.Attach(entity);

            var updateEntity = _context.Update<TEntity>(entity).Entity;

            if (autoSave)
            {
                await _context.SaveChangesAsync(cancellationToken);
            }

            return updateEntity;
        }

        public async Task UpdateManyAsync(IEnumerable<TEntity> entities, bool autoSave = false, CancellationToken cancellationToken = default)
        {
            _context.Set<TEntity>().UpdateRange(entities);

            if(autoSave)
            {
                await _context.SaveChangesAsync(cancellationToken);
            }
        }
    }
}
